function [rvalue] = subsref(hIniFile, S)
% BVQXinifile::subsref  - retrieve information via struct notation
%
% FORMAT:       inistruct = IniFileObject.STRUCT
%        or     section   = IniFileObject.Section
%        or     setting   = IniFileObject.Section.Setting
%
%    For multi-dimensional object arrays, the typical indexing is valid.
%    However, only singular objects may be used for instant

% Version:      v0.7b
% Build:        7090311
% Date:         Sep-03 2007, 11:35 AM CEST
% Author:       Jochen Weber, Brain Innovation, B.V., Maastricht, NL
% URL / Info:   http://wiki.brainvoyager.com/BVQXtools

% get method names for alias properties
global bvqxinifile_methods;
if isempty(bvqxinifile_methods)
    methods(hIniFile);
end

% argument check
if isempty(S)
    error( ...
        'BVQXinifile:BadSubsRef', ...
        'S struct may not be empty.' ...
    );
end
slen  = length(S);
stype = S(1).type;
ssubs = S(1).subs;

% decide on kind of subscripting, first struct-like notation
switch stype, case {'.'}
    
    % check for subscript type
    if ~ischar(ssubs) || ...
        isempty(ssubs)
        error( ...
            'BVQXinifile:BadSubsRef', ...
            'Struct notation needs a non-empty char subscript.' ...
        );
    end
    
    % only works for singular object
    if numel(hIniFile) ~= 1
        error( ...
            'BVQXinifile:InvalidFileID', ...
            'Struct notation only works for valid, singular objects.' ...
        );
    end
    
    % make content linear
    ssubs = ssubs(:)';
    
    % methods prevail
    mflds = fieldnames(bvqxinifile_methods);
    mfound = find(strcmpi(ssubs, mflds));
    if ~isempty(mfound) && ...
        slen == 1 && ...
        isempty(bvqxinifile_methods.(mflds{mfound}))
        try
            rvalue = BVQXinifile(hIniFile, lower(mflds{mfound}));
        catch
            rethrow(lasterror);
        end
        return;
    end
    
    % allow rest only for "good" objects
    if hIniFile.L == 0
        error( ...
            'BVQXinifile:InvalidObject', ...
            'Other calls/requests only allowed for non-root objects.' ...
        );
    end

    % complete or section ?
    if slen == 1
        
        % complete requested
        if strcmp(ssubs, 'STRUCT')
            rvalue = BVQXinifile(hIniFile, 'getcomplete');
        
        % section requested
        else
            try
                rvalue = BVQXinifile(hIniFile, 'getinisection', ssubs);
            catch
                rethrow(lasterror);
            end
        end
        
    % setting or subsetting
    else
        
        % method call
        if ~isempty(mfound) && ...
           strcmp(S(2).type, '()')
            
            % check argument count
            oargs = bvqxinifile_methods.(mflds{mfound});
            fargs = S(2).subs;
            if numel(fargs) > numel(oargs)
                error( ...
                    'BVQXinifile:TooManyArguments', ...
                    'Too many arguments for call to %s.', ...
                    mflds{mfound} ...
                );
            end
            
            % check args
            argok = true;
            for ac = 1:numel(fargs)
                oarg = oargs{ac};
                if oarg(1) == '['
                    oarg(1) = [];
                end
                if isempty(regexpi(class(fargs{ac}), oarg))
                    argok = false;
                    break;
                end
            end
            if ~argok
                error( ...
                    'BVQXinifile:BadArgument', ...
                    'Invalid arguments supplied in call to %s.', ...
                    mflds{mfound} ...
                );
            end
            if numel(fargs) < numel(oargs) && ...
                oargs{numel(fargs) + 1}(1) ~= '['
                error( ...
                    'BVQXinifile:BadArgument', ...
                    'Missing %d. argument of type %s in call to %s.', ...
                    numel(fargs) + 1, ...
                    oargs{numel(fargs) + 1}(3:end - 1), ...
                    mflds{mfound} ...
                );
            end

            try
                rvalue = BVQXinifile(hIniFile, lower(mflds{mfound}), fargs{:});
            catch
                rethrow(lasterror);
            end
            return;
        
        % require second subscript to also be CHAR
        elseif ~strcmp(S(2).type, '.') || ...
           ~ischar(S(2).subs) || ...
            isempty(S(2).subs)
            error( ...
                'BVQXinifile:BadSubsRef', ...
                'At least two CHAR struct subscripts are needed.' ...
            );
        end
        
        % get setting
        rvalue = BVQXinifile(hIniFile, 'getinisetting', S(1).subs, S(2).subs);
        
        % subsetting requested
        if length(S) > 2
            try
                rvalue = subsref(rvalue, S(3:end));
            catch
                error( ...
                    'BVQXinifile:IllegalSubsRef', ...
                    'Couldn''t pass subsref to %s.%s.', ...
                    S(1).subs, ...
                    S(2).subs ...
                );
            end
        end
    end
    
% indexing requested
case {'()'}
    
    % we need non-empty cell subscript
    if ~iscell(ssubs) || ...
        isempty(ssubs)
        error( ...
            'BVQXinifile:BadSubsRef', ...
            'Can''t index into BVQXinifile matrix.' ...
        );
    end
    
    % convert hIniFile to struct
    sIniFile = struct(hIniFile);
    
    % try to retrieve subscripted matrix
    try
        subset   = subsref(sIniFile, S(1));
        hIniFile = class(subset, 'BVQXinifile');
    catch
        error( ...
            'BVQXinifile:BadSubsRef', ...
            'Invalid subscript (%s).', ...
            lasterr ...
        );
    end
    
    % return sub-matrix if only one subscript
    if slen == 1
        rvalue = hIniFile;
        return;
    end
    
    if numel(hIniFile) ~= 1 || ...
       ~hIniFile.L
        error( ...
            'BVQXinifile:InvalidFileID', ...
            'Further subscripting only works for valid, singular objects.' ...
        );
    end
    
    rvalue = subsref(hIniFile, S(2:end));
    
otherwise
    error( ...
        'BVQXinifile:BadSubsRef', ...
        'Only struct notation allowed to retrieve values.' ...
    );
end
